﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Microsoft.Ccr.Core;
using System.Threading;
using System.Collections;
using System.Reflection;

namespace test.XcoAppSpaces.Core
{
	/*[TestFixture]
	public class testCcrCausalities
	{
	    private Port<NullReferenceException> exceptionPort1;
	    private Port<ArgumentException> exceptionPort2;

	    private Port<Exception> testPort;

        private AutoResetEvent are;


        [SetUp]
        public void SetupTests()
        {
            exceptionPort1 = new Port<NullReferenceException>();
            exceptionPort2 = new Port<ArgumentException>();

            testPort = new Port<Exception>();
        }

		[Test]
		public void TestCausalityBug()
		{
			this.are = new AutoResetEvent(false);

			using (Dispatcher d = new Dispatcher())
			{
				DispatcherQueue dpq = new DispatcherQueue("dpq", d);

				Dispatcher.AddCausality(new Causality("c1", exceptionPort1));
				Dispatcher.AddCausality(new Causality("c2", exceptionPort2)); //this causality seems to overwrite the first one
				//Note: When removing c2, c1 becomes active again... So, 2 causalities at the same time not possible??
				DumpActiveCausalities();

				Dispatcher.RemoveCausality("c2");
				
				//Dispatcher.ClearCausalities();
				FixCausalityTableBug();

				DumpActiveCausalities();
				
				Dispatcher.AddCausality(new Causality("c2", exceptionPort2));
				Dispatcher.RemoveCausality("c2");

				DumpActiveCausalities();
				
			}
		}

		private static void FixCausalityTableBug()
		{
			// Hack into Dispatcher object to get the table of causalities stack bound to specific thread.
			FieldInfo ctf = typeof(Dispatcher).GetField("_causalityTable", BindingFlags.Static | BindingFlags.NonPublic);
			IDictionary ct = ctf.GetValue(null) as IDictionary;

			// Get the CausalityThreadContext of the current thread.
			object cx = ct[Thread.CurrentThread.ManagedThreadId];
			if (cx == null) return;

			// If the stacks member is null, null-out CausalityTable too.
			FieldInfo stackFi = cx.GetType().GetField("Stacks", BindingFlags.NonPublic | BindingFlags.Instance);
			if (stackFi.GetValue(cx) == null)
			{
				FieldInfo causalityTable = cx.GetType().GetField("CausalityTable", BindingFlags.NonPublic | BindingFlags.Instance);
				causalityTable.SetValue(cx, null);
			}
		}



		[Test]
		public void TestMultipleCausalities()
		{
		    this.are = new AutoResetEvent(false);

			using(Dispatcher d = new Dispatcher())
			{
			    DispatcherQueue dpq = new DispatcherQueue("dpq", d);

			    Arbiter.Activate(
                    dpq,
                    Arbiter.Receive<NullReferenceException>(true, exceptionPort1, ReceiveException),
                    Arbiter.Receive<ArgumentException>(true, exceptionPort2, ReceiveException)
                    );

			    Dispatcher.AddCausality(new Causality("c1", exceptionPort1));
			    Dispatcher.AddCausality(new Causality("c2", exceptionPort2)); //this causality seems to overwrite the first one
			    //Note: When removing c2, c1 becomes active again... So, 2 causalities at the same time not possible??
                DumpActiveCausalities();

			    Arbiter.Activate(dpq, Arbiter.Receive(true, testPort, ThrowException));

                testPort.Post(new ArgumentException());
                Assert.IsTrue(are.WaitOne(1000), "failed to receive argument ex");
                testPort.Post(new NullReferenceException());
			    Assert.IsTrue(are.WaitOne(1000), "failed to receive null ref ex");
			}
		}


        [Test]
        public void TestCausalityStack()
        {
            using (Dispatcher d = new Dispatcher())
            {
                DispatcherQueue dpq = new DispatcherQueue("dpq", d);

                Port<Exception> pCatchAll = new Port<Exception>();
                Port<NullReferenceException> pCatchNull = new Port<NullReferenceException>();
                Port<ArgumentException> pCatchArg = new Port<ArgumentException>();

                //List<Causality> causalities;
                Dispatcher.AddCausality(new Causality("catch all", pCatchAll));
                foreach(Causality c in Dispatcher.ActiveCausalities)
                    Console.WriteLine(c.Name);

                Dispatcher.AddCausality(new Causality("catch null", pCatchNull));
                foreach (Causality c in Dispatcher.ActiveCausalities)
                    Console.WriteLine(c.Name);

                Dispatcher.AddCausality(new Causality("catch arg", pCatchArg));
                foreach (Causality c in Dispatcher.ActiveCausalities)
                    Console.WriteLine(c.Name);

                Dispatcher.RemoveCausality("catch null");
                foreach (Causality c in Dispatcher.ActiveCausalities)
                    Console.WriteLine(c.Name);

                Dispatcher.RemoveCausality("catch arg");
                foreach (Causality c in Dispatcher.ActiveCausalities)
                    Console.WriteLine(c.Name);
            }
        }


        [Test]
        public void TestNestedCausalities()
        {
            this.are = new AutoResetEvent(false);

            using (Dispatcher d = new Dispatcher())
            {
                DispatcherQueue dpq = new DispatcherQueue("dpq", d);
                Arbiter.Activate(
                    dpq,
                    Arbiter.Receive<NullReferenceException>(true, exceptionPort1, ReceiveException),
                    Arbiter.Receive<ArgumentException>(true, exceptionPort2, ReceiveException)
                    );

                Dispatcher.AddCausality(new Causality("c1", exceptionPort1));

                Arbiter.Activate(dpq, Arbiter.Receive(true, testPort, ThrowException));

                testPort.Post(null);
                Assert.IsTrue(are.WaitOne(1000), "failed to receive auto generated argument ex");
                testPort.Post(new NullReferenceException());
                Assert.IsTrue(are.WaitOne(1000), "failed to receive null ref ex");
                testPort.Post(new ArgumentException());
                Assert.IsTrue(are.WaitOne(1000), "failed to receive manual arg ex");
            }
        }



		private void ThrowException(Exception ex)
		{
            if (ex != null)
                Console.WriteLine("Message received: " + ex.GetType().Name);
            else
                Console.WriteLine("Message received: null");

		    DumpActiveCausalities();

            if (ex != null)
			    throw ex;
            else
            {
                Console.WriteLine("   Nesting causality");
                Dispatcher.AddCausality(new Causality("c2", exceptionPort2));
                DumpActiveCausalities();
                testPort.Post(new ArgumentException());
            }
		}

        private void ReceiveException(Exception ex)
        {
            Console.WriteLine("Ex received: " + ex.GetType().Name);
            DumpActiveCausalities();
            are.Set();
        }


        private void DumpActiveCausalities()
        {
            foreach (Causality c in Dispatcher.ActiveCausalities) //only one of the two causalities is found here...
            {
                Console.WriteLine("      Active causality: " + c.Name);
            }
        }
	}*/
}
